import { forEachValue } from "./utils";
import ModuleCollection from "./module/module-collection";
let Vue;

class Store {
  constructor(options) {
    //容器的初始化
    const state = options.state;
    // 实现mutations actions
    this._mutations = Object.create(null); // 存放mutation
    this._actions = Object.create(null); // 存放action
    this._wrappedGetters = Object.create(null); // 存放getter
    this._subscribers = []; // 存放plguin中的subscriber
    // 数据收集
    this._modules = new ModuleCollection(options);
    // 安装模块
    installModule(this, state, [], this._modules.root);
    // 创建实例
    resetStoreVM(this, state);
    //插件
    options.plugins.forEach((plugin) => {
      plugin(this);
    });
  }
  replaceState = (state) => {
    this._vm._data.$$state = state;
  };
  subscribe = (fn) => {
    this._subscribers.push(fn);
  };
  commit = (type, payload) => {
    this._mutations[type].forEach((mutation) => {
      mutation.call(this, payload);
    });
  };
  dispatch = (type, payload) => {
    this._actions[type].forEach((action) => {
      action.call(this, payload);
    });
  };
  get state() {
    //属性访问器
    return this._vm._data.$$state;
  }
}
// 注册实例
function resetStoreVM(store, state) {
  const computed = Object.create(null);
  const wrappedGetters = store._wrappedGetters;
  store.getters = Object.create(null);
  forEachValue(wrappedGetters, (fn, key) => {
    computed[key] = () => {
      return fn();
    };
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key],
      enumerable: true,
    });
  });
  store._vm = new Vue({
    data: {
      // 属性是$开头的 默认不会将这个属性挂载到实例上
      $$state: state, // 会将$$state对应的属性 通过defineProperty来进行响应式
    },
    computed,
  });
}
// 注册模块
/**
 *
 * @param {*} store 容器
 * @param {*} rootState 根模块
 * @param {*} path 路径
 * @param {*} module ModuleCollection
 */
// 获取最新状态
function getState(store,path) {
  return path.reduce((newState,current)=>{
    return newState[current]
  },store.state)
}
function installModule(store, rootState, path, module) {
  // 命名空间
  const namespace = store._modules.getNamespace(path);

  // 将子模块状态挂载副模块状态上
  if (path.length > 0) {
    let parentState = path.slice(0, -1).reduce((memo, current) => {
      return memo[current];
    }, rootState);
    Vue.set(parentState, path[path.length - 1], module.state);
  }
  // 递归调用子模块
  module.forEachChild((child, key) => {
    installModule(store, rootState, path.concat(key), child);
  });
  // 遍历当前模块 actions mutations getters
  module.forEachGetter((getter, key) => {
    store._wrappedGetters[namespace + key] = function() {
      return getter(getState(store,path));
    };
  });

  module.forEachAction((action, key) => {
    store._actions[namespace + key] = store._actions[namespace + key] || [];
    store._actions[namespace + key].push((payload) => {
      action.call(store, store, payload);
    });
  });

  module.forEachMutation((mutation, key) => {
    store._mutations[namespace + key] = store._mutations[namespace + key] || [];
    store._mutations[namespace + key].push((payload) => {
      mutation.call(store, getState(store,path), payload);
      store._subscribers.forEach((fn) => {
        fn(mutation, store.state);
      });
    });
  });
}

// 注册方法
const install = (_Vue) => {
  if (Vue && _Vue === Vue) return;
  Vue = _Vue;
  // 声明周期挂载
  Vue.mixin({ beforeCreate: vuexInit });
};

// Vuex初始化
function vuexInit() {
  const options = this.$options;
  if (options.store) {
    // 根节点添加store属性
    this.$store = options.store;
  } else if (options.parent && options.parent.$store) {
    // 非根节点 从副节点继承store
    this.$store = options.parent.$store;
  }
}

export { Store, install };
